#include <cstdlib>
#include <iostream>

#include "../include/contest_interface.h"
#include "../include/IteratorLink.h"
#include "../include/util.h"

IteratorLink::IteratorLink() {
    this->_next = NULL;
    this->_previous = NULL;
    this->current = NULL;
}

IteratorLink::IteratorLink(Record * _current) {
    this->_next = NULL;
    this->_previous = NULL;
    this->current = _current;
}

IteratorLink::~IteratorLink() {
    this->current = NULL;
    if (this->_next != NULL)
        this->_next->_previous = this->_previous;
    if (this->_previous != NULL)
        this->_previous->_next = this->_next;

    this->_next = NULL;
    this->_previous = NULL;
}

/**
 * used to call the destructor
 * If deleteRecord is true, then it will free the memory used by the record
 */
void IteratorLink::release(bool deleteRecord) {
    if (deleteRecord) {
        try {
            free(this->current->payload.data);
        } catch (...) {
        }
        this->current->payload.size = 0;
    }

    this->~IteratorLink();
}

/**
 * Return the record to which the iterator refers
 *
 * @return value of current iterator_link
 */
Record* IteratorLink::value() {
    return this->current;
}

/**
 * Insert new record in iterator_link list (insertion sort)
 *
 * @return true if no error
 */
IteratorLink* IteratorLink::insert(Record * new_record) throw (ErrorCode) {
    IteratorLink * currentI = this;
    IteratorLink * new_iterator;

    if (this->current == NULL) {
        this->current = new_record;
        return this;
    }

    try {
        new_iterator = new IteratorLink(new_record);
    } catch (...) {
        throw kErrorOutOfMemory;
    }

    try {
        // Case new is smaller then first
        if (recordCmp(*(currentI->current), *new_record) >= 0) {
            new_iterator->_next = currentI;
            currentI->_previous = new_iterator;

            return new_iterator;
        }

        while ((currentI->hasNext()) && (recordCmp(*(currentI->_next->current), *new_record) < 0))
            currentI = currentI->_next;

        new_iterator->_next = currentI->_next;
        new_iterator->_previous = currentI;
        currentI->_next = new_iterator;

        if (new_iterator->_next != NULL)
            new_iterator->_next->_previous = new_iterator;

        currentI = NULL;
    } catch (...) {
        throw kErrorGenericFailure;
    }
    return this;
}

/**
 * Get next iterator_link
 *
 * @return pointer to next element
 */
IteratorLink* IteratorLink::next() {
    return this->_next;
}

/**
 * Get previous iterator_link
 *
 * @return pointer to previous element
 */
IteratorLink* IteratorLink::previous() {
    return this->_previous;
}

/**
 * Changes the current pointer value
 */
void IteratorLink::setValue(Record *r, bool deleteRecords) {
    if (deleteRecords) {
        try {
            free(this->current->payload.data);
        } catch (...) {
        }
    }

    this->current = r;
}

/**
 * Changes the current pointer value
 */
void IteratorLink::setValue(Record *r) {
    this->current = r;
}

/**
 * Check if there is a next element
 *
 * @return true if this.next not NULL
 */
bool IteratorLink::hasNext() {
    return (this->next() != NULL);
}

/**
 * Check if there is a previous element
 *
 * @return true if this.previous not NULL
 */
bool IteratorLink::isFirst() {
    return (this->previous() == NULL);
}
